using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using ERP.ERPModels.Production.MasterData;
using ERP.ERPModels.RepositoryManage;
using ERP.MasterData.Dtos;
using ERP.RepositoryManage.Dtos;
using Microsoft.Extensions.Logging;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;

namespace ERP.RepositoryManage
{
    public class ProcurementService : ApplicationService, IProcurementService
    {
        private readonly IRepository<Procurement, int> _procurementRepository;
        private readonly IRepository<ProcurementDetail, int> _procurementDetailRepository;
        private readonly IRepository<Supplier, int> _supplierRepository;
        private readonly IRepository<Material, int> _materialRepository;
        private readonly IRepository<MaterialType, int> _materialTypeRepository;
        private readonly IRepository<Inventory, int> _inventoryRepository;
        private readonly IRepository<Warehouse, int> _warehouseRepository;
        private readonly ILogger<ProcurementService> _logger;

        public ProcurementService(
            IRepository<Procurement, int> procurementRepository,
            IRepository<ProcurementDetail, int> procurementDetailRepository,
            IRepository<Supplier, int> supplierRepository,
            IRepository<Material, int> materialRepository,
            IRepository<MaterialType, int> materialTypeRepository,
            IRepository<Inventory, int> inventoryRepository,
            IRepository<Warehouse, int> warehouseRepository,
            ILogger<ProcurementService> logger)
        {
            _procurementRepository = procurementRepository;
            _procurementDetailRepository = procurementDetailRepository;
            _supplierRepository = supplierRepository;
            _materialRepository = materialRepository;
            _materialTypeRepository = materialTypeRepository;
            _inventoryRepository = inventoryRepository;
            _warehouseRepository = warehouseRepository;
            _logger = logger;
        }

        /// <summary>
        /// 获取采购入库列表
        /// </summary>
        public async Task<PagedResultDto<ProcurementDto>> GetListAsync(GetProcurementInputDto input)
        {
            var query = await CreateFilteredQueryAsync(input);

            var totalCount = query.Count();

            query = ApplySorting(query, input);
            query = query.PageBy(input.SkipCount, input.MaxResultCount);

            var items = query.ToList();

            return new PagedResultDto<ProcurementDto>(
                totalCount,
                ObjectMapper.Map<List<Procurement>, List<ProcurementDto>>(items)
            );
        }

        /// <summary>
        /// 获取采购入库详情
        /// </summary>
        public async Task<ProcurementDto> GetAsync(int id)
        {
            var procurement = await _procurementRepository.GetAsync(id);
            var result = ObjectMapper.Map<Procurement, ProcurementDto>(procurement);

            // 获取明细
            result.Details = await GetDetailsAsync(id);

            return result;
        }

        /// <summary>
        /// 创建采购入库
        /// </summary>
        public async Task<ProcurementDto> CreateAsync(CreateProcurementDto input)
        {
            // 检查入库单编号是否已存在
            var existingProcurement = await _procurementRepository.FirstOrDefaultAsync(x => x.LnboundCode == input.LnboundCode);
            if (existingProcurement != null)
            {
                throw new UserFriendlyException("入库单编号已存在");
            }

            var procurement = ObjectMapper.Map<CreateProcurementDto, Procurement>(input);
            procurement.DocumentStatus = 0; // 默认草稿状态

            await _procurementRepository.InsertAsync(procurement);
            await CurrentUnitOfWork.SaveChangesAsync();

            return ObjectMapper.Map<Procurement, ProcurementDto>(procurement);
        }

        /// <summary>
        /// 更新采购入库
        /// </summary>
        public async Task<ProcurementDto> UpdateAsync(int id, UpdateProcurementDto input)
        {
            var procurement = await _procurementRepository.GetAsync(id);

            // 只有草稿状态才能修改
            if (procurement.DocumentStatus != 0)
            {
                throw new UserFriendlyException("只有草稿状态的入库单才能修改");
            }



            ObjectMapper.Map(input, procurement);

            await _procurementRepository.UpdateAsync(procurement);
            await CurrentUnitOfWork.SaveChangesAsync();

            return ObjectMapper.Map<Procurement, ProcurementDto>(procurement);
        }

        /// <summary>
        /// 删除采购入库
        /// </summary>
        public async Task DeleteAsync(int id)
        {
            var procurement = await _procurementRepository.GetAsync(id);

            // 只有草稿状态才能删除
            if (procurement.DocumentStatus != 0)
            {
                throw new UserFriendlyException("只有草稿状态的入库单才能删除");
            }

            // 删除明细
            var details = await _procurementDetailRepository.GetListAsync(x => x.ProcurementId == id);
            foreach (var detail in details)
            {
                await _procurementDetailRepository.DeleteAsync(detail);
            }

            await _procurementRepository.DeleteAsync(id);
            await CurrentUnitOfWork.SaveChangesAsync();
        }

        /// <summary>
        /// 执行入库操作
        /// </summary>
        public async Task ExecuteInboundAsync(int id)
        {
            var procurement = await _procurementRepository.GetAsync(id);

            if (procurement.DocumentStatus == 2)
            {
                throw new UserFriendlyException("该入库单已完成，无需重复操作");
            }

            // 获取入库明细
            var details = await _procurementDetailRepository.GetListAsync(x => x.ProcurementId == id);
            if (!details.Any())
            {
                throw new UserFriendlyException("请先添加入库明细");
            }

            // 如果是草稿状态，先更改为待入库状态
            if (procurement.DocumentStatus == 0)
            {
                procurement.DocumentStatus = 1; // 更新为待入库状态
                await _procurementRepository.UpdateAsync(procurement);
                await CurrentUnitOfWork.SaveChangesAsync();
                _logger.LogInformation("入库单 {Code} 状态更新为待入库", procurement.LnboundCode);
                return;
            }

            // 如果是待入库状态，执行入库操作
            if (procurement.DocumentStatus == 1)
            {
                // 更新库存
                foreach (var detail in details)
                {
                    await UpdateInventoryAsync(detail);
                }

                // 更新入库单状态为已完成
                procurement.DocumentStatus = 2;
                await _procurementRepository.UpdateAsync(procurement);
                await CurrentUnitOfWork.SaveChangesAsync();

                _logger.LogInformation("入库单 {Code} 执行入库操作成功", procurement.LnboundCode);
            }
        }

        /// <summary>
        /// 生成入库单编号
        /// </summary>
        public Task<string> GenerateInboundCodeAsync()
        {
            // 生成入库单编号：BK + 年月日时分秒毫秒
            string code = "BK" + DateTime.Now.ToString("yyyyMMddHHmmssfff");
            return Task.FromResult(code);
        }

        /// <summary>
        /// 获取采购入库明细列表
        /// </summary>
        public async Task<List<ProcurementDetailDto>> GetDetailsAsync(int procurementId)
        {
            var query = from detail in await _procurementDetailRepository.GetQueryableAsync()
                        join material in await _materialRepository.GetQueryableAsync() on detail.MaterialId equals material.Id into materialGroup
                        from material in materialGroup.DefaultIfEmpty()
                        join warehouse in await _warehouseRepository.GetQueryableAsync() on detail.WarehouseId equals warehouse.Id into warehouseGroup
                        from warehouse in warehouseGroup.DefaultIfEmpty()
                        where detail.ProcurementId == procurementId
                        select new ProcurementDetailDto
                        {
                            Id = detail.Id,
                            ProcurementId = detail.ProcurementId,
                            MaterialId = detail.MaterialId,
                            WarehouseId = detail.WarehouseId,
                            InputNum = detail.InputNum,
                            Money = detail.Money,
                            Batch = detail.Batch ?? "",
                            InDate = detail.InDate,
                            IsChecked = detail.IsChecked,
                            Desc = detail.Desc ?? "",
                            MaterialCode = material != null ? material.MaterielCode ?? "" : "",
                            MaterialName = material != null ? material.MaterielName ?? "" : "",
                            Specifications = material != null ? material.Specifications ?? "" : "",
                            Unit = material != null ? material.UnitsId ?? "" : "",
                            WarehouseName = warehouse != null ? warehouse.WarehouseName ?? "" : ""
                        };

            var result = query.ToList();
            
            // 记录调试信息
            _logger.LogInformation("获取采购入库明细，采购单ID: {ProcurementId}, 明细数量: {Count}", procurementId, result.Count);
            
            return result;
        }

        /// <summary>
        /// 添加采购入库明细
        /// </summary>
        public async Task<ProcurementDetailDto> AddDetailAsync(CreateProcurementDetailDto input)
        {
            var procurement = await _procurementRepository.GetAsync(input.ProcurementId);

            // 只有草稿状态才能添加明细
            if (procurement.DocumentStatus != 0)
            {
                throw new UserFriendlyException("只有草稿状态的入库单才能添加明细");
            }

            var detail = ObjectMapper.Map<CreateProcurementDetailDto, ProcurementDetail>(input);

            await _procurementDetailRepository.InsertAsync(detail);
            await CurrentUnitOfWork.SaveChangesAsync();

            // 返回包含物料信息和仓库信息的明细
            var material = await _materialRepository.FirstOrDefaultAsync(x => x.Id == detail.MaterialId);
            var warehouse = await _warehouseRepository.FirstOrDefaultAsync(x => x.Id == detail.WarehouseId);
            var result = ObjectMapper.Map<ProcurementDetail, ProcurementDetailDto>(detail);
            result.MaterialCode = material?.MaterielCode ?? "";
            result.MaterialName = material?.MaterielName ?? "";
            result.Specifications = material?.Specifications ?? "";
            result.Unit = material?.UnitsId ?? "";
            result.WarehouseName = warehouse?.WarehouseName ?? "";

            return result;
        }

        /// <summary>
        /// 删除采购入库明细
        /// </summary>
        public async Task DeleteDetailAsync(int detailId)
        {
            var detail = await _procurementDetailRepository.GetAsync(detailId);
            var procurement = await _procurementRepository.GetAsync(detail.ProcurementId);

            // 只有草稿状态才能删除明细
            if (procurement.DocumentStatus != 0)
            {
                throw new UserFriendlyException("只有草稿状态的入库单才能删除明细");
            }

            await _procurementDetailRepository.DeleteAsync(detailId);
            await CurrentUnitOfWork.SaveChangesAsync();
        }

        /// <summary>
        /// 获取供应商选择列表
        /// </summary>
        public async Task<PagedResultDto<SupplierSelectDto>> GetSupplierSelectListAsync(GetSupplierSelectInputDto input)
        {
            var query = await _supplierRepository.GetQueryableAsync();

            // 过滤条件
            if (!string.IsNullOrWhiteSpace(input.SupplierCode))
            {
                query = query.Where(x => x.SupplierCode.Contains(input.SupplierCode));
            }

            if (!string.IsNullOrWhiteSpace(input.SupplierName))
            {
                query = query.Where(x => x.SupplierName.Contains(input.SupplierName));
            }

            if (input.IsNo.HasValue)
            {
                query = query.Where(x => x.IsNo == input.IsNo.Value);
            }

            var totalCount = query.Count();

            query = query.OrderBy(x => x.SupplierCode)
                         .PageBy(input.SkipCount, input.MaxResultCount);

            var items = query.ToList();

            return new PagedResultDto<SupplierSelectDto>(
                totalCount,
                ObjectMapper.Map<List<Supplier>, List<SupplierSelectDto>>(items)
            );
        }

        /// <summary>
        /// 获取物料选择列表
        /// </summary>
        public async Task<PagedResultDto<MaterialSelectDto>> GetMaterialSelectListAsync(GetMaterialSelectInputDto input)
        {
            var query = from material in await _materialRepository.GetQueryableAsync()
                        join materialType in await _materialTypeRepository.GetQueryableAsync() on material.MaterielTypeld equals materialType.Id into typeGroup
                        from materialType in typeGroup.DefaultIfEmpty()
                        select new { material, materialType };

            // 过滤条件
            if (!string.IsNullOrWhiteSpace(input.MaterielCode))
            {
                query = query.Where(x => x.material.MaterielCode.Contains(input.MaterielCode));
            }

            if (!string.IsNullOrWhiteSpace(input.MaterielName))
            {
                query = query.Where(x => x.material.MaterielName.Contains(input.MaterielName));
            }

            if (input.MaterielTypeld.HasValue)
            {
                query = query.Where(x => x.material.MaterielTypeld == input.MaterielTypeld.Value);
            }

            if (input.IsNo.HasValue)
            {
                query = query.Where(x => x.material.IsNo == input.IsNo.Value);
            }

            var totalCount = query.Count();

            query = query.OrderBy(x => x.material.MaterielCode)
                         .PageBy(input.SkipCount, input.MaxResultCount);

            var items = query.Select(x => new MaterialSelectDto
            {
                Id = x.material.Id,
                MaterielCode = x.material.MaterielCode,
                MaterielName = x.material.MaterielName,
                Specifications = x.material.Specifications,
                UnitsId = x.material.UnitsId,
                Unit = x.material.UnitsId, // 将UnitsId作为单位名称显示
                MaterielTypeld = x.material.MaterielTypeld,
                MaterialTypeName = x.materialType != null ? x.materialType.TypeName : "",
                IsNo = x.material.IsNo
            }).ToList();

            return new PagedResultDto<MaterialSelectDto>(
                totalCount,
                items
            );
        }

        /// <summary>
        /// 获取物料类型树
        /// </summary>
        public async Task<List<MaterialTypeTreeDto>> GetMaterialTypeTreeAsync()
        {
            var allTypes = await _materialTypeRepository.GetListAsync();

            var rootTypes = allTypes.Where(x => x.ParentId == 0).ToList();

            var result = new List<MaterialTypeTreeDto>();

            foreach (var rootType in rootTypes)
            {
                var treeDto = new MaterialTypeTreeDto
                {
                    Id = rootType.Id,
                    title = rootType.TypeName,
                    ParentId = rootType.ParentId,
                    Children = BuildChildren(rootType.Id, allTypes)
                };
                result.Add(treeDto);
            }

            return result;
        }

        /// <summary>
        /// 创建过滤查询
        /// </summary>
        private async Task<IQueryable<Procurement>> CreateFilteredQueryAsync(GetProcurementInputDto input)
        {
            var query = await _procurementRepository.GetQueryableAsync();

            if (!string.IsNullOrWhiteSpace(input.LnboundCode))
            {
                query = query.Where(x => x.LnboundCode.Contains(input.LnboundCode));
            }

            if (!string.IsNullOrWhiteSpace(input.LnboundName))
            {
                query = query.Where(x => x.LnboundName.Contains(input.LnboundName));
            }

            if (!string.IsNullOrWhiteSpace(input.Vendor))
            {
                query = query.Where(x => x.Vendor.Contains(input.Vendor));
            }

            if (input.DocumentStatus.HasValue)
            {
                query = query.Where(x => x.DocumentStatus == input.DocumentStatus.Value);
            }

            if (input.StartDate.HasValue)
            {
                query = query.Where(x => x.LnboundDate >= input.StartDate.Value);
            }

            if (input.EndDate.HasValue)
            {
                query = query.Where(x => x.LnboundDate <= input.EndDate.Value);
            }

            return query;
        }

        /// <summary>
        /// 应用排序
        /// </summary>
        private IQueryable<Procurement> ApplySorting(IQueryable<Procurement> query, GetProcurementInputDto input)
        {
            if (!string.IsNullOrWhiteSpace(input.Sorting))
            {
                return query.OrderBy(input.Sorting);
            }

            return query.OrderByDescending(x => x.Id);
        }

        /// <summary>
        /// 构建子节点
        /// </summary>
        private List<MaterialTypeTreeDto> BuildChildren(int parentId, List<MaterialType> allTypes)
        {
            var children = allTypes.Where(x => x.ParentId == parentId).ToList();
            var result = new List<MaterialTypeTreeDto>();

            foreach (var child in children)
            {
                var childDto = new MaterialTypeTreeDto
                {
                    Id = child.Id,
                    title = child.TypeName,
                    ParentId = child.ParentId,
                    Children = BuildChildren(child.Id, allTypes)
                };
                result.Add(childDto);
            }

            return result;
        }

        /// <summary>
        /// 获取仓库选择列表
        /// </summary>
        public async Task<List<WarehouseSelectDto>> GetWarehouseSelectListAsync()
        {
            var warehouses = await _warehouseRepository.GetListAsync();
            return warehouses.Select(x => new WarehouseSelectDto
            {
                Id = x.Id,
                WarehouseName = x.WarehouseName,
                WarehouseAddress = x.WarehouseAddress
            }).ToList();
        }

        /// <summary>
        /// 更新库存
        /// </summary>
        private async Task UpdateInventoryAsync(ProcurementDetail detail)
        {
            var material = await _materialRepository.GetAsync(detail.MaterialId);

            // 查找现有库存
            var existingInventory = await _inventoryRepository.FirstOrDefaultAsync(x =>
                x.ProductItem == material.MaterielCode &&
                x.Storage == detail.Batch);

            if (existingInventory != null)
            {
                // 更新现有库存
                existingInventory.GalleryNumber += detail.InputNum;
                await _inventoryRepository.UpdateAsync(existingInventory);
            }
            else
            {
                // 创建新库存记录
                var inventory = new Inventory
                {
                    ProductItem = material.MaterielCode,
                    ProductName = material.MaterielName,
                    Specs = material.Specifications ?? "",
                    GalleryNumber = detail.InputNum,
                    Unit = material.UnitsId,
                    Storage = detail.Batch,
                    Warehouse = "默认仓库", // 可以根据实际情况调整
                    ReservoirArea = "",
                    BinLocation = "",
                    SupplierNumber = "",
                    SupplierName = "",
                    SupplierAbbreviatio = "",
                    ProduceTickets = "",
                    StorageDate = detail.InDate,
                    Storagevalidity = detail.InDate.AddYears(1) // 默认一年有效期
                };

                await _inventoryRepository.InsertAsync(inventory);
            }
        }
    }
} 